基于人脸识别的课堂签到管理系统【学习四】

您所在的位置:网站首页 爱课堂 签到 基于人脸识别的课堂签到管理系统【学习四】

基于人脸识别的课堂签到管理系统【学习四】

2024-02-04 13:49| 来源: 网络整理| 查看: 265

今天改变了昨天在运行窗口显示的人脸信息的方式,把基本信息显示到ui界面,这主要是通过设计两个窗口部件textEdit用来显示这些信息,进行解析完成把信息依次添加到窗口中。还讲了人脸识别的操作,由于原来10ms获取画面只用作,显示画面是流畅的。但是每500ms发送网络请求,调用post函数,等待返回结果,就会存在一定的等待时间,程序就在这里阻塞执行,那10ms会调用的显示函数就不会执行了,所以会存在一定卡顿现象。所以为了解决这个问题,所以就采用多线程方式解决卡顿现象,通过把进行人脸检测的操作交给新的线程去完成)通过创建一个新的线程,每500ms去执行post请求这种耗时操作。实现方式post请求是摄像头交给线程,线程进行采集,窗口采集,把画面转换成base64交给线程,当获取画面后,就把数据交给线程的函数:使用信号槽,当获取画面就产生信号,连接线程的检测函数。

在返回的结果中,在face_list列表中,每一项值就是一个人脸信息,每个人脸信息用字典来表示,字典中包含什么信息由发送请求的参数face_field键值决定

返回结果内容的解析通过for循环取出每个字典数据(人脸),进行单独解析

解析数据后,进行显示

人脸信息显示: 设计两个窗口部件(textEdit)用来显示信息 进行解析完成把信息依此添加到窗口中

人脸识别操作: 从摄像头获取画面,进行人脸检测函数的调用,当调用一次函数就检测一次 但是百度网络API的QPS为2(每秒只有2次) 完成网络请求限制,需要单独去设置人脸检测(500ms),每500ms额外再获取一次摄像头画面,这次获取就用作检测(通过设置定时器,产生信号,关联槽函数,完成功能)

原先10ms获取画面只用作,显示画面(流畅)

每500ms发送网络请求,调用post函数,等待返回结果,就会存在一定的等待时间,程序就在这里阻塞执行,那10ms会调用的显示函数就不会执行了,所以会存在一定卡顿现象

采用 多线程方式 解决卡顿现象(把进行人脸检测的操作交给新的线程去完成) 通过创建一个新的线程,去执行post请求这种耗时操作(每500ms执行一次)

实现方式(post请求): 摄像头交给线程,线程进行采集 窗口采集,把画面转换成base64交给线程 当获取画面后,就把数据交给线程的函数:使用信号槽,当获取画面就产生信号,连接线程的检测函数

今日份详细代码

main.py代码如下

import sys from PyQt5.QtWidgets import QApplication from mywindow import mywindow ''' 程序的解释执行文件 ''' if __name__ == '__main__': #创建应用程序对象 app = QApplication(sys.argv) #创建窗口 ui = mywindow() #显示窗口 ui.show() #应用执行 app.exec_() sys.exit(0)

mywindow.py代码如下:

import base64 import cv2 import requests from mainwindow import Ui_MainWindow from PyQt5.QtWidgets import QMainWindow, QFileDialog from PyQt5.QtCore import QTimer, QDateTime, QDate, QTime, pyqtSignal from cameravideo import camera from detect import detect_thread ''' 子类,继承Ui_MainWindow与QMainWindow Ui_MainWindow: 包含是界面的设计,窗口中的窗口部件 QMainWindow: 包含是整个界面窗口,窗口的操作 mywindow: 完整的窗口类 ''' class mywindow(Ui_MainWindow, QMainWindow): detect_data_signal = pyqtSignal(str) def __init__(self): super(mywindow, self).__init__() self.setupUi(self) # 创建界面内容 # 创建一个定时器对象 self.datetime = QTimer(self) # 启动获取系统日期时间定时器,定时时间为500ms,500ms产生一次信号 self.datetime.start(500) # 创建窗口就应该完成访问令牌的申请(获取) self.get_accesstoken() # 信号与槽的关联 # self.actionopen:指定对象 # triggered:信号 # connect:关联(槽函数) # self.on_actionclose:关联的函数是什么 self.actionopen.triggered.connect(self.on_actionopen) # 停止签到 self.actionclose.triggered.connect(self.on_actionclose) # 关联时间日期的定时器信号与槽函数 self.datetime.timeout.connect(self.date_time) # self.pushButton_3.clicked.connect(self.get_accesstoken) # self.pushButton.clicked.connect(self.get_face) # 创建线程完成检测 # 函数功能获取日期与时间,添加到对应编辑器中 def date_time(self): # 获取日期 date = QDate.currentDate() # print(date) # self.dateEdit.setDate(date) self.label_2.setText(date.toString()) # 获取时间 time = QTime.currentTime() # print(time) # self.timeEdit.setTime(time) self.label_3.setText(time.toString()) # 获取日期时间 # datetime = QDateTime.currentDateTime() # print(datetime) ''' 信号槽功能: 当某个组件设计了信号槽功能时,当信号产生,会主动调用槽函数,去完成对应的一个功能 信号:当以某种特定的操作,操作这个组件时,就会主动产生对应操作的信号 ''' def on_actionclose(self): # print("on_actionclose") # 关闭摄像头 self.cameravideo.close_camera() # 关闭定时器,不再去获取摄像头数据 self.timeshow.stop() self.label.setText("摄像头画面显示") def on_actionopen(self): # print("on_actionopen") # 启动摄像头 self.cameravideo = camera() # 启动定时器,进行定时,每隔多长时间进行一次获取摄像头数据并进行显示 self.timeshow = QTimer(self) self.timeshow.start(10) # 10ms的定时器启动,每到10ms就会产生一个信号timeout self.timeshow.timeout.connect(self.show_cameradata) # 创建检测线程 self.create_thread() # 开启检测启动时,创建定时器,500ms,用作获取要检测的画面 self.facedetecttime = QTimer(self) self.facedetecttime.start(500) self.facedetecttime.timeout.connect(self.get_cameradata) self.detect_data_signal.connect(self.detectThread.detect_face) def create_thread(self): self.detectThread = detect_thread(self.access_token) self.detectThread.start() def get_cameradata(self): # 摄像头获取画面 camera_data = self.cameravideo.read_camera() # 转换为把摄像头画面转换成图片,然后设置base64编码格式数据 _, enc = cv2.imencode('.jpg', camera_data) base64_image = base64.b64encode(enc.tobytes()) # 产生信号,传递数据 self.detect_data_signal.emit(str(base64_image)) # 是作为摄像头,获取数据,显示画面功能 # 只要能够不断调用这个函数,不断的从摄像头获取数据进行显示 # 可以通过信号,信号关联当前函数,只要信号产生,函数就会被调用 # 信号需要不断产生,可以通过定时器,定时时间到达就会产生信号 def show_cameradata(self): # self.cameravideo = camera() # 获取摄像头数据,转换数据 pic = self.cameravideo.camera_to_pic() # 显示数据,显示画面 self.label.setPixmap(pic) # 获取进行网络请求的访问令牌 def get_accesstoken(self): # print("get") # client_id 为官网获取的AK, client_secret 为官网获取的SK # host是字符串,存储授权的服务地址---获取accesstoken的地址 host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=exGfN5ZtUhTgZGHZVV8v821I&client_secret=iXyHXkgxqCwzDigifG5Bq9FQY4nCPDaS' # 发送网络请求 response = requests.get(host) if response: # print(response.json()) data = response.json() self.access_token = data.get('access_token') # self.access_token = response['access_token'] # print(self.access_token) # 进行人脸检测功能 def get_face(self): ''' #这是打开对话框获取 #获取一张图片或一帧画面 #通过对话框的形式获取一个图片的路径 path, ret = QFileDialog.getOpenFileName(self, "open picture", ".", "图片格式(*.jpg)") print(path) #把图片转换成base64编码 fp = open(path, 'rb') base64_image = base64.b64encode(fp.read()) ''' # 摄像头获取画面 camera_data = self.cameravideo.read_camera() # 转换为把摄像头画面转换成图片,然后设置base64编码格式数据 _, enc = cv2.imencode('.jpg', camera_data) base64_image = base64.b64encode(enc.tobytes()) # 发送请求的地址 request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect" # 请求参数,是一个字典,存储了百度AI要识别的图片信息,要识别的属性内容 params = {"image": base64_image, # 图片信息字符串 "image_type": "BASE64", # 图片信息的格式 "face_field": "gender,age,beauty,expression,face_shape,glasses,mask,emotion", # 请求识别人脸的属性,在各个属性字符串用逗号隔开 "max_face_num": 10 } # 访问令牌 access_token = self.access_token # 把请求地址和访问令牌组成可用的网络请求地址 request_url = request_url + "?access_token=" + access_token # 设置请求格式体 headers = {'content-type': 'application/json'} # 发送网络post请求,请求百度API进行人脸检测,返回检测结果 # 发送网络请求,会等待一定时间,所以会导致程序在这里阻塞执行 response = requests.post(request_url, data=params, headers=headers) if response: # print(response.json()) data = response.json() if data['error_msg'] == 'SUCCESS': # 在data字典中,键为'result'对应的值才是返回的检测结果 # data['result']就是检测结果 # 人脸数目 self.plainTextEdit_2.clear() face_num = data['result']['face_num'] if face_num == 0: self.plainTextEdit_2.appendPlainText("当前没有人脸出现") return else: self.plainTextEdit_2.appendPlainText("存在及人脸出现") # 人脸信息: data['result']['face_list']是列表,每个数据就是一个人脸 # 每个人脸信息: data['result']['face_list'][0~i]人脸信息字典 for i in range(face_num): # 通过for循环,分别取出列表的每一个数据 # data['result']['face_list'][i]就是每一个人脸信息的字典 age = data['result']['face_list'][i]['age'] beauty = data['result']['face_list'][i]['beauty'] gender = data['result']['face_list'][i]['gender']['type'] expression = data['result']['face_list'][i]['expression']['type'] face_shape = data['result']['face_list'][i]['face_shape']['type'] glasses = data['result']['face_list'][i]['glasses']['type'] mask = data['result']['face_list'][i]['mask']['type'] emotion = data['result']['face_list'][i]['emotion']['type'] # 往窗口中添加文本,参数就是需要的文本信息 self.plainTextEdit_2.appendPlainText(str(i + 1) + "学生人脸信息") self.plainTextEdit_2.appendPlainText("年龄是:" + str(age)) self.plainTextEdit_2.appendPlainText("颜值分数是:" + str(beauty)) self.plainTextEdit_2.appendPlainText("性别是:" + str(gender)) self.plainTextEdit_2.appendPlainText("表情是:" + str(expression)) self.plainTextEdit_2.appendPlainText("脸型是:" + str(face_shape)) self.plainTextEdit_2.appendPlainText("是否佩戴眼镜:" + str(glasses)) self.plainTextEdit_2.appendPlainText("情绪是:" + str(emotion)) if mask == 0: mask = "否" else: mask = "是" self.plainTextEdit_2.appendPlainText("是否佩戴口罩:" + str(mask)) # print(age) # print(beauty) # print(gender) # print(expression) # print(face_shape) # print(glasses) # print(emotion) # print(mask) # print(data['result']) # 在data字典中,键为‘result’对应的值才是返回的检测结果

cameravideo.py代码如下:

import cv2 import numpy as np from PyQt5.QtGui import QPixmap, QImage ''' 摄像头操作:创建类对象完成摄像头操作,使用可以把打开摄像头与创建类对象操作合并 __init__函数完成摄像头的配置打开 ''' class camera(): # 摄像头的配置打开与创建类对象合并 def __init__(self): # VideoCapture类对视频或调用摄像头进行读取操作 # 参数 filename;device # 0表示默认的摄像头,进行打开 #创建摄像头对象,打开摄像头 #self.capture表示打开摄像头的对象 self.capture = cv2.VideoCapture(0, cv2.CAP_DSHOW) if self.capture.isOpened(): print("isopenned") #定义一个多维数组,用来存储获取的 self.currentframe = np.array([]) # 读取摄像头数据 def read_camera(self): ret, pic_data = self.capture.read() if not ret: print("获取摄像头数据失败") return None return pic_data # 把数据转换成界面能显示的数据格式 def camera_to_pic(self): pic = self.read_camera() # 摄像头是BGR方式存储,需要转换成RGB # 调用cvtColor完成后才是RGB格式的画面数据 self.currentframe = cv2.cvtColor(pic, cv2.COLOR_BGR2RGB) # 设置宽高 # self.currentframe = cv2.cvtColor(self.currentframe, (640, 480)) # 转换为界面能够显示的格式 # 获取画面的宽度与高度 height, width = self.currentframe.shape[:2] # 先转换为QImage类型图片(画面),创建QImage类对象,使用摄像头画面数据 # QImage(data,width,height,format)创建:数据,宽度,高度,格式 qimg = QImage(self.currentframe, width, height, QImage.Format_RGB888) qpixmap = QPixmap.fromImage(qimg) return qpixmap # 摄像头关闭 def close_camera(self): self.capture.release()

detect.py代码如下:

from PyQt5.QtCore import QThread, QTimer import requests import cv2 import base64 # Thread就是PyQt5提供的线程类 # 由于是一个已经完成了的类,功能已经写好,线程的功能需要我们自己完成 # 需要自己完成需要的线程类,创建一个新的线程类(功能可以自己定义),继承QThread,新写的类就是线程类,具备线程功能 # 线程进行执行只会执行线程类中的run函数,如果有新的功能需要实现,重写一个run函数 class detect_thread(QThread): def __init__(self, token): super(detect_thread, self).__init__() self.access_token = token # run函数执行结束,代表线程结束 def run(self): print("run") ''' self.time = QTimer() self.time.start(1000) self.time.timeout.connect(self.detect_face) ''' self.exec_() # 进行人脸检测功能 def detect_face(self,base64_image): ''' 这是打开对话框获取 #获取一张图片或一帧画面 #通过对话框的形式获取一个图片的路径 path, ret = QFileDialog.getOpenFileName(self, "open picture", ".", "图片格式(*.jpg)") print(path) #把图片转换成base64编码 fp = open(path, 'rb') base64_image = base64.b64encode(fp.read()) ''' # 发送请求的地址 request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect" # 请求参数,是一个字典,存储了百度AI要识别的图片信息,要识别的属性内容 params = {"image": base64_image, # 图片信息字符串 "image_type": "BASE64", # 图片信息的格式 "face_field": "gender,age,beauty,expression,face_shape,glasses,mask,emotion", # 请求识别人脸的属性,在各个属性字符串用逗号隔开 "max_face_num": 10 } # 访问令牌 access_token = self.access_token # 把请求地址和访问令牌组成可用的网络请求地址 request_url = request_url + "?access_token=" + access_token # 设置请求格式体 headers = {'content-type': 'application/json'} # 发送网络post请求,请求百度API进行人脸检测,返回检测结果 # 发送网络请求,会等待一定时间,所以会导致程序在这里阻塞执行 response = requests.post(request_url, data=params, headers=headers) if response: # print(response.json()) data = response.json() print(data)

今天的基本情况 在这里插入图片描述人脸信息显示窗口部件(textEdit)显示信息效果 在这里插入图片描述最终实现的效果 在这里插入图片描述(今天任务完成了的,但是这个返回结果存在问题,姚老师说明天会继续详细的讲解。)

今天,上午跟上了老师的节奏,遇见了一个小错误,就是在设计ui界面时没有注意到TextEdit的名称和老师的不一样,导致运作界面的时候出现闪退,问了老师,老师帮我分析了代码很久也没找到具体的错误,最后自己去看了ui界面,发现了错误并改正了(主要还是粗心),但是也更加熟悉了如何把ui界面与系统程序关联的方法。下午的时候总体还是好的,老师就带我们实现多线程并发解决卡顿问题。这里我觉得有点混乱,老师时不时的讲了几种方法,导致自己不是太明白,但是下课时老师说了明天还会具体讲,所以应该没什么问题,自己也要再继续看回放消化消化了。

作为物联网小白,个人能力有限,今天是我们学习人脸识别的课堂签到管理系统的第四天,肯定有很多不足,后面会慢慢改正。

谢谢姚老师!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3